//! Plugin Actor
//! 
//! This actor manages Extism WebAssembly plugins,
//! providing multi-language extension capabilities.

use crate::actors::messages::*;
use crate::error::Result;
use crate::models::{
    plugin::{PluginInfo, PluginManifest, PluginType, PluginStatus},
    Value, ValueMap,
};
use coerce::actor::Actor;
use coerce::actor::context::ActorContext;
use coerce::actor::message::Handler;
use async_trait::async_trait;
use std::collections::HashMap;
use uuid::Uuid;

/// Plugin Actor
#[derive(Debug)]
pub struct PluginActor {
    /// Loaded plugins
    plugins: HashMap<String, PluginInfo>,
}

impl PluginActor {
    /// Create a new plugin actor
    pub fn new() -> Self {
        Self {
            plugins: HashMap::new(),
        }
    }
    
    /// Load a plugin
    async fn load_plugin(&mut self, path: String, config: ValueMap) -> Result<PluginResponse> {
        tracing::info!("Loading plugin from: {}", path);
        
        // TODO: Implement actual plugin loading with Extism
        let plugin_id = Uuid::new_v4().to_string();
        let manifest = PluginManifest::new(
            "test_plugin".to_string(),
            "1.0.0".to_string(),
            PluginType::Wasm,
        );
        
        let plugin_info = PluginInfo::new(manifest.clone(), path);
        self.plugins.insert(plugin_id.clone(), plugin_info);
        
        Ok(PluginResponse::PluginLoaded {
            plugin_id,
            manifest,
        })
    }
    
    /// Call a plugin function
    async fn call_function(
        &self,
        plugin_id: String,
        function_name: String,
        args: Vec<Value>,
    ) -> Result<PluginResponse> {
        // TODO: Implement actual function calling with Extism
        Ok(PluginResponse::FunctionResult {
            result: Value::String("Function result placeholder".to_string()),
        })
    }
    
    /// Unload a plugin
    async fn unload_plugin(&mut self, plugin_id: String) -> Result<PluginResponse> {
        if self.plugins.remove(&plugin_id).is_some() {
            Ok(PluginResponse::PluginUnloaded { plugin_id })
        } else {
            Ok(PluginResponse::Error {
                message: format!("Plugin not found: {}", plugin_id),
            })
        }
    }
    
    /// List all plugins
    async fn list_plugins(&self) -> Result<PluginResponse> {
        let plugins: Vec<PluginInfo> = self.plugins.values().cloned().collect();
        Ok(PluginResponse::PluginList { plugins })
    }
    
    /// Get plugin information
    async fn get_plugin_info(&self, plugin_id: String) -> Result<PluginResponse> {
        if let Some(info) = self.plugins.get(&plugin_id) {
            Ok(PluginResponse::PluginInfo {
                info: info.clone(),
            })
        } else {
            Ok(PluginResponse::Error {
                message: format!("Plugin not found: {}", plugin_id),
            })
        }
    }
}

#[async_trait]
impl Actor for PluginActor {
    async fn started(&mut self, _ctx: &mut ActorContext) {
        tracing::info!("PluginActor started");
    }
}

#[async_trait]
impl Handler<PluginMessage> for PluginActor {
    async fn handle(&mut self, msg: PluginMessage, _ctx: &mut ActorContext) -> PluginResponse {
        match msg {
            PluginMessage::LoadPlugin { path, config } => {
                match self.load_plugin(path, config).await {
                    Ok(response) => response,
                    Err(e) => PluginResponse::Error {
                        message: e.to_string(),
                    },
                }
            }

            PluginMessage::CallFunction { plugin_id, function_name, args } => {
                match self.call_function(plugin_id, function_name, args).await {
                    Ok(response) => response,
                    Err(e) => PluginResponse::Error {
                        message: e.to_string(),
                    },
                }
            }

            PluginMessage::UnloadPlugin { plugin_id } => {
                match self.unload_plugin(plugin_id).await {
                    Ok(response) => response,
                    Err(e) => PluginResponse::Error {
                        message: e.to_string(),
                    },
                }
            }

            PluginMessage::ListPlugins => {
                match self.list_plugins().await {
                    Ok(response) => response,
                    Err(e) => PluginResponse::Error {
                        message: e.to_string(),
                    },
                }
            }

            PluginMessage::GetPluginInfo { plugin_id } => {
                match self.get_plugin_info(plugin_id).await {
                    Ok(response) => response,
                    Err(e) => PluginResponse::Error {
                        message: e.to_string(),
                    },
                }
            }
        }
    }
}
